<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>CreateJS Example: Space Rocks Game</title>
	
	
	<script>
		// this sets the namespace for CreateJS to the window object, so you can instantiate objects without specifying 
		// the namespace: "new Graphics()" instead of "new createjs.Graphics()"
		// this is a quick way to make projects built on pervious versions of EaselJS run without extensive modifications
	</script>
	
	<script type="text/javascript" src="assets/preloadjs-NEXT.min.js"></script>
	<script type="text/javascript" src="assets/soundjs-NEXT.min.js"></script>

	<!-- Note: All core EaselJS classes are listed here: -->
	<script type="text/javascript" src="../src/createjs/events/Event.js"></script>
	<script type="text/javascript" src="../src/createjs/events/EventDispatcher.js"></script>
	<script type="text/javascript" src="../src/createjs/utils/IndexOf.js"></script>
	<script type="text/javascript" src="../src/easeljs/utils/UID.js"></script>
	<script type="text/javascript" src="../src/easeljs/utils/Ticker.js"></script>
	<script type="text/javascript" src="../src/easeljs/geom/Matrix2D.js"></script>
	<script type="text/javascript" src="../src/easeljs/geom/Point.js"></script>
	<script type="text/javascript" src="../src/easeljs/geom/Rectangle.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/Shadow.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/SpriteSheet.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/Graphics.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/DisplayObject.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/Container.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/Stage.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/Bitmap.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/Sprite.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/BitmapAnimation.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/BitmapText.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/Shape.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/Text.js"></script>
	<script type="text/javascript" src="../src/easeljs/display/DOMElement.js"></script>
	<script type="text/javascript" src="../src/easeljs/events/MouseEvent.js"></script>
	<script type="text/javascript" src="../src/easeljs/filters/Filter.js"></script>
	<script type="text/javascript" src="../src/easeljs/ui/ButtonHelper.js"></script>
	<script type="text/javascript" src="../src/easeljs/ui/Touch.js"></script>
	<script type="text/javascript" src="../src/easeljs/utils/SpriteSheetUtils.js"></script>
	<script type="text/javascript" src="../src/easeljs/utils/SpriteSheetBuilder.js"></script>

	<!-- We also provide hosted minified versions of all CreateJS libraries.
	    http://code.createjs.com -->

	<!-- Game script below -->
	<script type="text/javascript" src="assets/SpaceRock.js"></script>
	<script type="text/javascript" src="assets/Ship.js"></script>
	<script>

	var DIFFICULTY = 2;			//how fast the game gets mor difficult
	var ROCK_TIME = 110;		//aprox tick count until a new asteroid gets introduced
	var SUB_ROCK_COUNT = 4;		//how many small rocks to make on rock death
	var BULLET_TIME = 5;		//ticks between bullets
	var BULLET_ENTROPY = 100;	//how much energy a bullet has before it runs out.

	var TURN_FACTOR = 7;		//how far the ship turns per frame
	var BULLET_SPEED = 17;		//how fast the bullets move

	var KEYCODE_ENTER = 13;		//usefull keycode
	var KEYCODE_SPACE = 32;		//usefull keycode
	var KEYCODE_UP = 38;		//usefull keycode
	var KEYCODE_LEFT = 37;		//usefull keycode
	var KEYCODE_RIGHT = 39;		//usefull keycode
	var KEYCODE_W = 87;			//usefull keycode
	var KEYCODE_A = 65;			//usefull keycode
	var KEYCODE_D = 68;			//usefull keycode

	var shootHeld;			//is the user holding a shoot command
	var lfHeld;				//is the user holding a turn left command
	var rtHeld;				//is the user holding a turn right command
	var fwdHeld;			//is the user holding a forward command

	var timeToRock;			//difficulty adjusted version of ROCK_TIME
	var nextRock;			//ticks left until a new space rock arrives
	var nextBullet;			//ticks left until the next shot is fired

	var rockBelt;			//space rock array
	var bulletStream;		//bullet array

	var canvas;			//Main canvas
	var stage;			//Main display stage

	var ship;			//the actual ship
	var alive;			//wheter the player is alive

	var messageField;		//Message display field
	var scoreField;			//score Field

	var loadingInterval = 0;

    var preload;

	//register key functions
	document.onkeydown = handleKeyDown;
	document.onkeyup = handleKeyUp;

	var preload;

	function init() {
	    if (window.top != window) {
	       document.getElementById("header").style.display = "none";
	   	}

        document.getElementById("mobile").style.display = "none";

	    if (!createjs.Sound.initializeDefaultPlugins()) {
	         document.getElementById("error").style.display = "block";
	         document.getElementById("content").style.display = "none";
	         return;
	    }

 		if (createjs.Sound.BrowserDetect.isIOS || createjs.Sound.BrowserDetect.isAndroid || createjs.Sound.BrowserDetect.isBlackberry) {
			document.getElementById("mobile").style.display = "block";
	        document.getElementById("content").style.display = "none";
	        return;
		}

		canvas = document.getElementById("gameCanvas");
		stage = new createjs.Stage(canvas);
		messageField = new createjs.Text("Loading", "bold 24px Arial", "#FFFFFF");
		messageField.maxWidth = 1000;
		messageField.textAlign = "center";
		messageField.x = canvas.width / 2;
		messageField.y = canvas.height / 2;
		stage.addChild(messageField);
		stage.update(); 	//update the stage to show text

		// begin loading content (only sounds to load)
		var manifest = [
			{id:"begin", src:"assets/Game-Spawn.mp3|../../assets/Game-Spawn.ogg"},
			{id:"break", src:"assets/Game-Break.mp3|../../assets/Game-Break.ogg", data:6},
			{id:"death", src:"assets/Game-Death.mp3|../../assets/Game-Death.ogg"},
			{id:"laser", src:"assets/Game-Shot.mp3|../../assets/Game-Shot.ogg", data:6},
			{id:"music", src:"assets/18-machinae_supremacy-lord_krutors_dominion.mp3|../../assets/18-machinae_supremacy-lord_krutors_dominion.ogg"}
		];

        preload = new createjs.LoadQueue();
        preload.installPlugin(createjs.Sound);
		preload.addEventListener("complete", doneLoading); // add an event listener for when load is completed
        preload.addEventListener("progress", updateLoading);
	    preload.loadManifest(manifest);
	}

	function stop() {
		if (preload != null) { preload.close(); }
		createjs.Sound.stop();
	}

	function updateLoading() {
		messageField.text = "Loading " + (preload.progress*100|0) + "%"
		stage.update();
	}


	function doneLoading(event) {
		clearInterval(loadingInterval);
		scoreField = new createjs.Text("0", "bold 12px Arial", "#FFFFFF");
		scoreField.textAlign = "right";
		scoreField.x = canvas.width - 10;
		scoreField.y = 22;
		scoreField.maxWidth = 1000;

		messageField.text = "Welcome: Click to play";

		// start the music
		createjs.Sound.play("music", createjs.Sound.INTERRUPT_NONE, 0, 0, -1, 0.4);

		watchRestart();
	}

	function watchRestart() {
		//watch for clicks
		stage.addChild(messageField);
		stage.update(); 	//update the stage to show text
		canvas.onclick = handleClick;
	}

	function handleClick() {
		//prevent extra clicks and hide text
		canvas.onclick = null;
		stage.removeChild(messageField);

		// indicate the player is now on screen
		createjs.Sound.play("begin");   

		restart();
	}

	//reset all game logic
	function restart() {
		//hide anything on stage and show the score
		stage.removeAllChildren();
		scoreField.text = (0).toString();
		stage.addChild(scoreField);

		//new arrays to dump old data
		rockBelt = [];
		bulletStream = [];

		//create the player
		alive = true;
		ship = new Ship();
		ship.x = canvas.width / 2;
		ship.y = canvas.height / 2;

		//log time untill values
		timeToRock = ROCK_TIME;
		nextRock = nextBullet = 0;

		//reset key presses
		shootHeld =	lfHeld = rtHeld = fwdHeld = dnHeld = false;

		//ensure stage is blank and add the ship
		stage.clear();
		stage.addChild(ship);

		//start game timer   
		if (!createjs.Ticker.hasEventListener("tick")) { 
			createjs.Ticker.addEventListener("tick", tick);
		}                                               
	}

	function tick(event) {
		//handle firing
		if(nextBullet <= 0) {
			if(alive && shootHeld){
				nextBullet = BULLET_TIME;
				fireBullet();
			}
		} else {
			nextBullet--;
		}

		//handle turning
		if(alive && lfHeld){
			ship.rotation -= TURN_FACTOR;
		} else if(alive && rtHeld) {
			ship.rotation += TURN_FACTOR;
		}

		//handle thrust
		if(alive && fwdHeld){
			ship.accelerate();
		}

		//handle new spaceRocks
		if(nextRock <= 0) {
			if(alive){
				timeToRock -= DIFFICULTY;	//reduce spaceRock spacing slowly to increase difficulty with time
				var index = getSpaceRock(SpaceRock.LRG_ROCK);
				rockBelt[index].floatOnScreen(canvas.width, canvas.height);
				nextRock = timeToRock + timeToRock*Math.random();
			}
		} else {
			nextRock--;
		}

		//handle ship looping
		if(alive && outOfBounds(ship, ship.bounds)) {
			placeInBounds(ship, ship.bounds);
		}

		//handle bullet movement and looping
		for(bullet in bulletStream) {
			var o = bulletStream[bullet];
			if(!o || !o.active) { continue; }
			if(outOfBounds(o, ship.bounds)) {
				placeInBounds(o, ship.bounds);
			}
			o.x += Math.sin(o.rotation*(Math.PI/-180))*BULLET_SPEED;
			o.y += Math.cos(o.rotation*(Math.PI/-180))*BULLET_SPEED;

			if(--o.entropy <= 0) {
				stage.removeChild(o);
				o.active = false;
			}
		}

		//handle spaceRocks (nested in one loop to prevent excess loops)
		for(spaceRock in rockBelt) {
			var o = rockBelt[spaceRock];
			if(!o || !o.active) { continue; }

			//handle spaceRock movement and looping
			if(outOfBounds(o, o.bounds)) {
				placeInBounds(o, o.bounds);
			}
			o.tick(event);


			//handle spaceRock ship collisions
			if(alive && o.hitRadius(ship.x, ship.y, ship.hit)) {
				alive = false;

				stage.removeChild(ship);
				messageField.text = "You're dead:  Click or hit enter to play again";
				stage.addChild(messageField);
				watchRestart();

				//play death sound
				createjs.Sound.play("death", createjs.Sound.INTERRUPT_ANY);
				continue;
			}

			//handle spaceRock bullet collisions
			for(bullet in bulletStream) {
				var p = bulletStream[bullet];
				if(!p || !p.active) { continue; }

				if(o.hitPoint(p.x, p.y)) {
					var newSize;
					switch(o.size) {
						case SpaceRock.LRG_ROCK: newSize = SpaceRock.MED_ROCK;
							break;
						case SpaceRock.MED_ROCK: newSize = SpaceRock.SML_ROCK;
							break;
						case SpaceRock.SML_ROCK: newSize = 0;
							break;
					}

					//score
					if(alive) {
						addScore(o.score);
					}

					//create more
					if(newSize > 0) {
						var i;
						var index;
						var offSet;

						for(i=0; i < SUB_ROCK_COUNT; i++){
							index = getSpaceRock(newSize);
							offSet = (Math.random() * o.size*2) - o.size;
							rockBelt[index].x = o.x + offSet;
							rockBelt[index].y = o.y + offSet;
						}
					}

					//remove
					stage.removeChild(o);
					rockBelt[spaceRock].active = false;

					stage.removeChild(p);
					bulletStream[bullet].active = false;

					// play sound
					createjs.Sound.play("break", createjs.Sound.INTERUPT_LATE, 0, 0.8);
				}
			}
		}

		//call sub ticks
		ship.tick(event);
		stage.update(event);
	}

	function outOfBounds(o, bounds) {
		//is it visibly off screen
		return o.x < bounds*-2 || o.y < bounds*-2 || o.x > canvas.width+bounds*2 || o.y > canvas.height+bounds*2;
	}

	function placeInBounds(o, bounds) {
		//if its visual bounds are entirely off screen place it off screen on the other side
		if(o.x > canvas.width+bounds*2) {
			o.x = bounds*-2;
		} else if(o.x < bounds*-2) {
			o.x = canvas.width+bounds*2;
		}

		//if its visual bounds are entirely off screen place it off screen on the other side
		if(o.y > canvas.height+bounds*2) {
			o.y = bounds*-2;
		} else if(o.y < bounds*-2) {
			o.y = canvas.height+bounds*2;
		}
	}

	function fireBullet() {
		//create the bullet
		var o = bulletStream[getBullet()];
		o.x = ship.x;
		o.y = ship.y;
		o.rotation = ship.rotation;
		o.entropy = BULLET_ENTROPY;
		o.active = true;

		//draw the bullet
		o.graphics.beginStroke("#FFFFFF").moveTo(-1, 0).lineTo(1, 0);

		// play the shot sound
		createjs.Sound.play("laser", createjs.Sound.INTERUPT_LATE);
	}

	function getSpaceRock(size) {
		var i = 0;
		var len = rockBelt.length;

		//pooling approach
		while(i <= len){
			if(!rockBelt[i]) {
				rockBelt[i] = new SpaceRock(size);
				break;
			} else if(!rockBelt[i].active) {
				rockBelt[i].activate(size);
				break;
			} else {
				i++;
			}
		}

		if(len == 0) {
			rockBelt[0] = new SpaceRock(size);
		}

		stage.addChild(rockBelt[i]);
		return i;
	}

	function getBullet() {
		var i = 0;
		var len = bulletStream.length;

		//pooling approach
		while(i <= len){
			if(!bulletStream[i]) {
				bulletStream[i] = new createjs.Shape();
				break;
			} else if(!bulletStream[i].active) {
				bulletStream[i].active = true;
				break;
			} else {
				i++;
			}
		}

		if(len == 0) {
			bulletStream[0] = new createjs.Shape();
		}

		stage.addChild(bulletStream[i]);
		return i;
	}

	//allow for WASD and arrow control scheme
	function handleKeyDown(e) {
		//cross browser issues exist
		if(!e){ var e = window.event; }
		switch(e.keyCode) {
			case KEYCODE_SPACE:	shootHeld = true; return false;
			case KEYCODE_A:
			case KEYCODE_LEFT:	lfHeld = true; return false;
			case KEYCODE_D:
			case KEYCODE_RIGHT: rtHeld = true; return false;
			case KEYCODE_W:
			case KEYCODE_UP:	fwdHeld = true; return false;
			case KEYCODE_ENTER:	 if(canvas.onclick == handleClick){ handleClick(); }return false;
		}
	}

	function handleKeyUp(e) {
		//cross browser issues exist
		if(!e){ var e = window.event; }
		switch(e.keyCode) {
			case KEYCODE_SPACE:	shootHeld = false; break;
			case KEYCODE_A:
			case KEYCODE_LEFT:	lfHeld = false; break;
			case KEYCODE_D:
			case KEYCODE_RIGHT: rtHeld = false; break;
			case KEYCODE_W:
			case KEYCODE_UP:	fwdHeld = false; break;
		}
	}

	function addScore(value) {
		//trust the field will have a number and add the score
		scoreField.text = (Number(scoreField.text) + Number(value)).toString();
	}

	</script>

	<link rel="stylesheet" type="text/css" href="assets/demoStyles.css" />
	<style type="text/css">
		#content {
			user-select: none;
			background-color:#000000;
			width: 960px;
			height: 400px;
		}
	</style>
</head>

<body onload="init();">

	<header id="header" class="SoundJS">
	    <h1><span class="text-product">Sound<strong>JS</strong></span> Space Rocks Game</h1>
	    <p>Example use of SoundJS for a game, built <a href="http://www.easeljs.com" target="_blank">EaselJS</a> a canvas management tool.
	        Music Copyright &copy; 2010 <a href="http://machinaesupremacy.com" target="_blank">Machinae Supremacy</a> - Lord Krutors Dominion. Used with permission for non commercial use.</p>
	</header>

	<div id="content">
		<canvas id="gameCanvas" width="960" height="400"></canvas>
	</div>

	<div id="error">
		<h1>Sorry!</h1>
		<p>SoundJS is not currently supported in your browser.</p>
		<p>We are currently working on support for iOS. Please <a href="http://github.com/CreateJS/SoundJS/issues" target="_blank">log a bug</a>
			if you see this in any other browsers.</p>
	</div>

    <div id="mobile">
        <h1>Sorry!</h1>
        <p>This demo is currenly not supported on mobile devices.</p>
    </div>

</body>
</html>
